home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / lang / mc302 / microcad / mcprint.c < prev    next >
C/C++ Source or Header  |  1994-03-18  |  12KB  |  456 lines

  1. /*
  2.  * MICROCAD Print Utility
  3.  *
  4.  * Copyright 1992-1994 Dave Dunfield
  5.  * All rights reserved.
  6.  *
  7.  * Permission granted for personal (non-commercial) use only.
  8.  *
  9.  * Compile command: cc mcprint -fop
  10.  */
  11. #include <stdio.h>
  12.  
  13. /* Screen dimensions */
  14. #define    VERTICAL        480        /* Maximum screen height */
  15. #define    HORIZONTAL        640        /* Maximum screen width */
  16.  
  17. #define    BUFSIZE            38400    /* Size of video buffer */
  18.  
  19. #define    ARC_RES            64        /* Resolution of each ARC quadrant */
  20.  
  21. #define    PBYTES            11        /* # of prefix bytes */
  22.  
  23. /* Drawing buffer codes */
  24. #define    LINE            0x01    /* Object is a LINE */
  25. #define    BOX                0x02    /* Object is a BOX */
  26. #define    CIRCLE            0x03    /* Object is a CIRCLE */
  27. #define    TEXT            0x04    /* Object is a TEXT string */
  28. #define    ARC                0x05    /* Object is an ARC */
  29. #define    GROUP            0x06    /* Object is a GROUP of objects */
  30. #define    ACOPY            0x07    /* Copy an object (absolute) */
  31. #define    RCOPY            0x08    /* Copy an object (relative) */
  32.  
  33. /* Drawing storage variables */
  34. unsigned char drawing[32000];
  35. unsigned dpos;
  36.  
  37. /* Misc. variables */
  38. char font[4608], dfile[65], ffile[65], *device = "LPT1";
  39. int vbseg, printer = -1;
  40.  
  41. /*
  42.  * Printer information: The variable 'printers' contains the names of
  43.  * All supported printer types. To add a new printer, add its name to
  44.  * this list, add its 'xyorder' flag to the 'xyorders' variable below,
  45.  * and add code to the 'switch' statement at the end of 'main()' to
  46.  * output the drawing.
  47.  */
  48. char *printers[] = {
  49.     "LASERJET",
  50.     "EPSON" }
  51.  
  52. /*
  53.  * The 'xyorder' flag controls how the bitmap image is generated.
  54.  *
  55.  * If xyorder is non-zero, the bitmap will be organized such that each
  56.  * byte contains bits from the same COLUMN. This is suitable for direct
  57.  * output to a "raster" type printer such as the LaserJet.
  58.  *
  59.  * If xyorder is zero, the bitmap will be organized such that each
  60.  * byte contains bits from the same ROW. This is suitable for
  61.  * direct output to a "dot matrix" type printer such as the EPSON.
  62.  *
  63.  * NOTE: The terms COLUMN and ROW are used with reference to the drawing,
  64.  *       which is printed SIDEWAYS. Therefore, the terms are reversed with
  65.  *       respect to the physical page layout of the printer.
  66.  */
  67. char xyorder, xyorders[] = {
  68.     -1,        /* Laserjet uses COLUMN alignment */
  69.     0 }        /* EPSON uses ROW alignment */
  70.  
  71. /* 
  72.  * Sine table for drawing ARC's
  73.  */
  74. unsigned sine[] = {
  75.         0,  1608,  3216,  4821,  6424,  8022,  9616, 11204,
  76.     12785, 14359, 15924, 17479, 19024, 20557, 22078, 23586,
  77.     25079, 26557, 28020, 29465, 30893, 32302, 33692, 35062,
  78.     36410, 37736, 39040, 40320, 41575, 42806, 44011, 45190,
  79.     46341, 47464, 48559, 49624, 50660, 51665, 52639, 53581,
  80.     54491, 55368, 56212, 57022, 57797, 58538, 59243, 59913,
  81.     60547, 61144, 61705, 62228, 62714, 63162, 63571, 63943,
  82.     64276, 64571, 64826, 65043, 65220, 65358, 65457, 65516 };
  83.  
  84. /*
  85.  * Main program - process commands at the highest level
  86.  */
  87. main(argc, argv)
  88.     int argc;
  89.     char *argv[];
  90. {
  91.     unsigned i, j;
  92.     char *ptr;
  93.     FILE *fp, *pfp;
  94.  
  95.     /* Set default file names */
  96.     *dfile = 0;
  97.     concat(ffile, "MICROCAD.FNT");
  98.  
  99.     /* Parse command line arguments */
  100.     for(i=1; i < argc; ++i) {
  101.         ptr = argv[i];
  102.         switch((toupper(*ptr++) << 8) | toupper(*ptr++)) {
  103.             case 'F=' :        /* Specify alternate FONT file */
  104.                 concat(ffile, ptr, ".FNT");
  105.                 break;
  106.             case 'D=' :        /* Specify output device */
  107.                 device = ptr;
  108.                 break;
  109.             case '?' << 8:    /* Command line help */
  110.             case '/?' :
  111.             case '-?' :
  112.                 goto help;
  113.             default:        /* Assume drawing filename or printer*/
  114.                 if(!*dfile) {    /* Need filename? */
  115.                     concat(dfile, argv[i], ".DWG");
  116.                     break; }
  117.                 for(ptr = argv[i]; *ptr; ++ptr)    /* Insure name uppercase */
  118.                     *ptr = toupper(*ptr);
  119.                 for(j=0; j < (sizeof(printers)/2); ++j) {    /* Lookup name */
  120.                     if(strbeg(printers[j], argv[i])) {
  121.                         if(printer != -1) {
  122.                             printf("Ambiguous printer name!\n");
  123.                             goto help; }
  124.                         printer = j; } }
  125.                 if(printer == -1) {
  126.                     printf("Unknown printer name!\n");
  127.                     goto help; } } }
  128.  
  129.     /* If insufficent parameters, or help request... output info */
  130.     if((printer == -1) || !*dfile) {
  131.         printf("Drawing name and printer type required!\n");
  132.     help:
  133.         printf("\nUse: MCPRINT <drawing file> <printer type> [F=font file] [D=device]\n");
  134.         printf("\nCopyright 1992-1994 Dave Dunfield\nAll rights reserved.\n\n");
  135.         printf("Available printers are:\n");
  136.         for(j=0; j < (sizeof(printers)/2); ++j)
  137.             printf("   %s\n", printers[j]);
  138.         exit(-1); }
  139.  
  140.     /* Read in "font" file */
  141.     fp = fopen(ffile, "rbvq");
  142.     fread(font, sizeof(font), fp);
  143.     fclose(fp);
  144.  
  145.     /* Read in the drawing file */
  146.     fp = fopen(dfile, "rbvq");
  147.     fread(drawing, PBYTES, fp);
  148.     i = fread(drawing, sizeof(drawing), fp);
  149.     fclose(fp);
  150.  
  151.     /* Zero unused portion of drawing file */
  152.     while(i < sizeof(drawing))
  153.         drawing[i++] = 0;
  154.  
  155.     /* Open printer device, and set for binary output */
  156.     set_raw(pfp = fopen(device, "wbvq"));
  157.  
  158.     /* Allocate buffer for printer */
  159.     printf("Initalize... ");
  160.     if(!(vbseg = alloc_seg((BUFSIZE+15)/16)))
  161.         abort("Not enough memory!");
  162.  
  163.     /* Zero the initial bitmap in the buffer */
  164.     for(i=0; i < BUFSIZE; ++i)
  165.         poke(vbseg, i, 0);
  166.  
  167.     /* Draw all the objects */
  168.     printf("Draw objects... ");
  169.     xyorder = xyorders[printer];
  170.     dpos = 0;
  171.     while(!draw_object(0, 0));
  172.  
  173.     printf("Print... ");
  174.  
  175.     /* Add code to this switch statement to support additional printers */
  176.     switch(printer) {
  177.         case 0 :        /* Laserjet raster format */
  178.             fprintf(pfp,"\x1B*t75R");            /* Set 75 Dots per inch */
  179.             fprintf(pfp,"\x1B*r0A");            /* Enable raster graphics */
  180.             for(dpos=i=0; i < HORIZONTAL; ++i) {
  181.                 fprintf(pfp,"\x1B*b60W");        /* Transfer graphics line */
  182.                 for(j=0; j < (VERTICAL/8); ++j)
  183.                     putc(peek(vbseg, dpos++), pfp); }
  184.             fprintf(pfp,"\x1B*rB\f");            /* End raster graphics */
  185.             break;
  186.         case 1 :        /* EPSON dot-matrix format */
  187.             for(i=0; i < (HORIZONTAL/8); ++i) {
  188.                 fprintf(pfp,"\x1BK\xE0\x01");    /* Graphics: 480 dots */
  189.                 for(j=0; j < BUFSIZE; j += (HORIZONTAL/8))
  190.                     putc(peek(vbseg, i + j), pfp);
  191.                 fprintf(pfp,"\r\x1BJ\x18"); }    /* Advance 8 lines */
  192.         }
  193.     
  194.     /* Close the output file & we are all done */
  195.     fclose(pfp);
  196.     printf("Done.");
  197. }
  198.  
  199. /*
  200.  * Draws an object from the drawing file
  201.  */
  202. draw_object(xoffset, yoffset)
  203.     int xoffset, yoffset;
  204. {
  205.     int x, y, i, j, k, l;
  206.     char buffer[80], *ptr;
  207.  
  208.     i = drawing[dpos++];
  209.     x = dvalue() + xoffset;
  210.     y = dvalue() + yoffset;
  211.  
  212.     switch(i) {
  213.         case LINE :
  214.             line(x, y, x+dvalue(), y+dvalue());
  215.             break;
  216.         case BOX :
  217.             box(x, y, x+dvalue(), y+dvalue());
  218.             break;
  219.         case CIRCLE :
  220.             circle(x, y, dvalue());
  221.             break;
  222.         case TEXT :
  223.             i = dvalue();
  224.             ptr = buffer;
  225.             do
  226.                 *ptr++ = j = drawing[dpos++];
  227.             while(j);
  228.             text(buffer, x, y, i);
  229.             break;
  230.         case ARC:
  231.             arc(x, y, dvalue(), dvalue(), dvalue());
  232.             break;
  233.         case GROUP :
  234.             i = dvalue();
  235.             j = dpos;
  236.             while((dpos - j) < i)
  237.                 draw_object(x, y);
  238.             break;
  239.         case RCOPY :
  240.             i = dpos - 5;
  241.             i += dvalue();
  242.             goto gocopy;
  243.         case ACOPY :
  244.             i = dvalue();
  245.         gocopy:
  246.             j = dpos;
  247.             dpos = i+1;
  248.             k = dvalue();
  249.             l = dvalue();
  250.             dpos = i;
  251.             draw_object(x - k, y - l);
  252.             dpos = j;
  253.             break;
  254.         default:
  255.             abort("Corrupt drawing file!");
  256.         case 0 :
  257.             return -1; }
  258.     return 0;
  259. }
  260.  
  261. /*
  262.  * Draw a line from point (x1, y1) to (x2, y2)
  263.  */
  264. line(x1, y1, x2, y2)
  265.     int x1, y1, x2, y2;
  266. {
  267.     int i, w, h;
  268.     /* If 'X' is greater, increment through 'X' coordinate */
  269.     if((w = abs(x1 - x2)) >= (h = abs(y1 - y2))) {
  270.         if(x1 > x2) {
  271.             i = x1;
  272.             x1 = x2;
  273.             x2 = i;
  274.             i = y1;
  275.             y1 = y2;
  276.             y2 = i; }
  277.         if(y1 < y2) {
  278.             for(i=0; i < w; ++i)
  279.                 set_pixel(x1+i, y1+scale(i, h, w)); }
  280.         else {
  281.             for(i=0; i < w; ++i)
  282.                 set_pixel(x1+i, y1-scale(i, h, w)); } }
  283.     /* If 'Y' is greater, increment through 'Y' coordinate */
  284.     else {
  285.         if(y1 > y2) {
  286.             i = x1;
  287.             x1 = x2;
  288.             x2 = i;
  289.             i = y1;
  290.             y1 = y2;
  291.             y2 = i; }
  292.         if(x1 < x2) {
  293.             for(i=0; i < h; ++i)
  294.                 set_pixel(x1+scale(i, w, h), y1+i); }
  295.         else {
  296.             for(i=0; i < h; ++i)
  297.                 set_pixel(x1-scale(i, w, h), y1+i); } }
  298.  
  299.     set_pixel(x2, y2);
  300. }
  301.  
  302. /*
  303.  * Draw a box with opposite corners (x1, y1) to (x2, y2)
  304.  */
  305. box(x1, y1, x2, y2)
  306.     int x1, y1, x2, y2;
  307. {
  308.     line(x1, y1, x2, y1);        /* Top */
  309.     line(x1, y1, x1, y2);        /* Left side */
  310.     line(x2, y1, x2, y2);        /* Right side */
  311.     line(x1, y2, x2, y2);        /* Bottom */
  312. }
  313.  
  314. /*
  315.  * Draw a circle about point (x, y) of radius (r)
  316.  */
  317. circle(x, y, r)
  318.     int x, y, r;
  319. {
  320.     int i, j, k, rs, lj;
  321.  
  322.     rs = (lj = r)*r;
  323.     for(i=0; i <= r; ++i) {
  324.         j = k = sqrt(rs - (i*i));
  325.         do {
  326.             set_pixel(x+i, y+j);
  327.             set_pixel(x+i, y-j);
  328.             set_pixel(x-i, y+j);
  329.             set_pixel(x-i, y-j); }
  330.         while(++j < lj);
  331.         lj = k; }
  332. }
  333.  
  334. /*
  335.  * Draw an arc centered at (x, y), radius r at vectors v1, v2
  336.  */
  337. arc(x, y, r, v1, v2)
  338.     int x, y, r;
  339.     unsigned char v1, v2;
  340. {
  341.     int rs, i, j, ax, x1, y1, x2, y2;
  342.  
  343.     x2 = -1;
  344.     rs = r*r;
  345.  
  346.     do {
  347.         j = (ARC_RES-1) - (i = v1 & (ARC_RES-1));
  348.         switch(v1 & (ARC_RES*3)) {
  349.             case ARC_RES*0 :    /* Quadrant one */
  350.                 x1 = x + (ax = scale(r, sine[i], -1));
  351.                 y1 = y - sqrt(rs - (ax*ax));
  352.                 break;
  353.             case ARC_RES*1 :    /* Quadrant two */
  354.                 x1 = x + (ax = scale(r, sine[j], -1));
  355.                 y1 = y + sqrt(rs - (ax*ax));
  356.                 break;
  357.             case ARC_RES*2 :    /* Quadrant three */
  358.                 x1 = x - (ax = scale(r, sine[i], -1));
  359.                 y1 = y + sqrt(rs - (ax*ax));
  360.                 break;
  361.             case ARC_RES*3 :    /* Quadrant four */
  362.                 x1 = x - (ax = scale(r, sine[j], -1));
  363.                 y1 = y - sqrt(rs - (ax*ax)); }
  364.         if(x2 != -1)
  365.             line(x2, y2, x1, y1);
  366.         x2 = x1;
  367.         y2 = y1; }
  368.     while(v1++ != v2);
  369. }
  370.  
  371. /*
  372.  * Draw a text string on the screen at specified scale
  373.  */
  374. text(string, x, y, s)
  375.     char *string;
  376.     int x, y, s;
  377. {
  378.     unsigned i, j, b;
  379.     unsigned char *ptr;
  380.  
  381.     y -= scale(24, s, 100);
  382.     while(*string) {
  383.         ptr = &font[(*string++ - ' ') * 48];
  384.  
  385.         for(i=0; i < 24; ++i) {
  386.             b = (*ptr++ << 8) | *ptr++;
  387.             for(j=0; j < 16; ++j) {
  388.                 if(b & 0x8000)
  389.                     set_pixel(x+scale(j,s,100), y+scale(i,s,100));
  390.                 b <<= 1; } }
  391.         x += scale(18, s, 100); }
  392. }
  393.  
  394. /*
  395.  * Retrieve a 16 bit value from the drawing list
  396.  */
  397. dvalue()
  398. {
  399.     return (drawing[dpos++] << 8) | drawing[dpos++];
  400. }
  401.  
  402. /*
  403.  * Set a graphic pixel in the output buffer.
  404.  */
  405. set_pixel(x, y)
  406.     unsigned x, y;
  407. {
  408.     unsigned byte;
  409.  
  410.     if((x < HORIZONTAL) && (y < VERTICAL)) {
  411.         y = (VERTICAL-1) - y;    /* Flip because printer outputs from bottom */
  412.  
  413.         if(xyorder) {    /* COLUMN alignment */
  414.             byte = (x * (VERTICAL/8)) + (y / 8);
  415.             poke(vbseg, byte, peek(vbseg, byte) | (0x80 >> (y % 8))); }
  416.         else {            /* ROM alignment */
  417.             byte = (y * (HORIZONTAL/8)) + (x / 8);
  418.             poke(vbseg, byte, peek(vbseg, byte) | (0x80 >> (x % 8))); } }
  419. }
  420.  
  421. /*
  422.  * Scale a value by a fraction, using a 32 bit intermediate result,
  423.  * and round up/down to nearest integer ressult.
  424.  */
  425. scale(value, mul, div) asm
  426. {
  427.         MOV        AX,8[BP]        ; Get value
  428.         MUL        WORD PTR 6[BP]    ; Multiply to 32 bit product
  429.         MOV        BX,4[BP]        ; Get divisor
  430.         DIV        BX                ; Divide back to 16 bit result
  431.         SHR        BX,1            ; /2 for test
  432.         JZ        scale1            ; Special case (/1)
  433.         INC        DX                ; .5 rounds up
  434.         SUB        BX,DX            ; Set 'C' if remainder > half
  435.         ADC        AX,0            ; Increment result to scale
  436. scale1:
  437. }
  438.  
  439. /*
  440.  * Set a device into "raw" mode for pure binary output
  441.  */
  442. set_raw(fp) asm
  443. {
  444.         MOV        BX,4[BP]        ; Get file pointer
  445.         MOV        AX,4400h        ; IOCTL:Get info
  446.         MOV        BX,1[BX]        ; Get DOS file handle
  447.         INT        21h                ; Ask DOS
  448.         TEST    DL,80h            ; Device?
  449.         JZ        setr1            ; Not a device...
  450.         XOR        DH,DH            ; Force DH=0
  451.         OR        DL,20h            ; Set RAM mode
  452.         MOV        AX,4401h        ; IOCTL:Set info
  453.         INT        21h                ; Ask DOS
  454. setr1:
  455. }
  456.